package cn.bby.tools.utils;

import cn.hutool.core.codec.Base64Decoder;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONUtil;
import com.google.zxing.*;
import com.google.zxing.client.j2se.BufferedImageLuminanceSource;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.common.HybridBinarizer;
import com.google.zxing.qrcode.QRCodeReader;
import com.google.zxing.qrcode.QRCodeWriter;
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.List;

/**
 * 字符串与二维码图片相互转换工具类
 *
 * @author: bby
 * @date: 2025/10/17 17:28
 * @version: 1.0
 */
public class StringImageUtil {

    public static final int DEFAULT_WIDTH = 700;
    public static final int DEFAULT_HEIGHT = 700;
    public static final char SPLIT_FLAG = ':';
    public static final int MAX_LENGTH_PAGE = 900;

    /**
     * 将字符串转换为二维码图片
     *
     * @param text 要转换的字符串
     * @return 生成的二维码图片文件
     */
    public static BufferedImage encode(String text) {
        try {
            // 使用QRCode编码（支持更大数据量）
            QRCodeWriter qrCodeWriter = new QRCodeWriter();

            Map<EncodeHintType, Object> hints = new EnumMap<>(EncodeHintType.class);
            hints.put(EncodeHintType.CHARACTER_SET, StandardCharsets.UTF_8.name());
            // 添加纠错等级以提高识别率
            hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.Q);

            // 生成矩阵 - QRCode支持更大数据量，最大可支持2953字节
            BitMatrix bitMatrix = qrCodeWriter.encode(text, BarcodeFormat.QR_CODE, DEFAULT_WIDTH, DEFAULT_HEIGHT, hints);

            // 获取矩阵尺寸
            int matrixWidth = bitMatrix.getWidth();
            int matrixHeight = bitMatrix.getHeight();

            // 创建BufferedImage
            BufferedImage image = new BufferedImage(matrixWidth, matrixHeight, BufferedImage.TYPE_INT_RGB);

            // 绘制二维码 - 直接操作像素，黑色为二维码点，白色为背景
            for (int x = 0; x < matrixWidth; x++) {
                for (int y = 0; y < matrixHeight; y++) {
                    if (bitMatrix.get(x, y)) {
                        image.setRGB(x, y, Color.BLACK.getRGB());
                    } else {
                        image.setRGB(x, y, Color.WHITE.getRGB());
                    }
                }
            }

            return image;
        } catch (Exception e) {
            throw new RuntimeException("Failed to generate QR code image", e);
        }
    }

    /**
     * 从二维码图片解码为字符串
     *
     * @param file 二维码图片文件
     * @return 解码后的字符串
     */
    public static String decodeSingle(File file) {
        try {
            // 读取图像
            BufferedImage image = ImageIO.read(file);

            // 创建光源和二值化图像
            LuminanceSource source = new BufferedImageLuminanceSource(image);
            BinaryBitmap bitmap = new BinaryBitmap(new HybridBinarizer(source));

            // 使用QRCode读取器
            QRCodeReader qrCodeReader = new QRCodeReader();
            Map<DecodeHintType, Object> hints = new EnumMap<>(DecodeHintType.class);
            hints.put(DecodeHintType.CHARACTER_SET, StandardCharsets.UTF_8.name());

            // 解码
            com.google.zxing.Result result = qrCodeReader.decode(bitmap, hints);

            // Base64解码返回原始文本
            return Base64Decoder.decodeStr(result.getText());
        } catch (Exception e) {
            throw new RuntimeException("Failed to decode QR code image", e);
        }
    }

    /**
     * 从二维码图片中解码出多个二维码内容
     *
     * @param file 二维码图片文件
     * @return 解码后的字符串列表
     */
    public static List<String> decodeMultipleToList(File file) {
        // 读取图像
        BufferedImage image = null;
        try {
            image = ImageIO.read(file);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        return decodeMultipleToList(image);

    }

    /**
     * 从二维码图片中解码出多个二维码内容
     *
     * @param image 二维码图片文件
     * @return 解码后的字符串列表
     */
    public static List<String> decodeMultipleToList(BufferedImage image) {
        List<String> res = new ArrayList<>();

        try {
            // 创建图像副本以避免修改原始图像
            BufferedImage imageCopy = new BufferedImage(image.getWidth(), image.getHeight(), image.getType());
            java.awt.Graphics2D g = imageCopy.createGraphics();
            g.drawImage(image, 0, 0, null);
            g.dispose();

            // 创建光源和二值化图像
            LuminanceSource source = new BufferedImageLuminanceSource(imageCopy);
            BinaryBitmap bitmap = new BinaryBitmap(new HybridBinarizer(source));

            // 使用MultiFormatReader来增强识别能力
            com.google.zxing.MultiFormatReader multiFormatReader = new com.google.zxing.MultiFormatReader();
            Map<DecodeHintType, Object> hints = new EnumMap<>(DecodeHintType.class);
            hints.put(DecodeHintType.CHARACTER_SET, StandardCharsets.UTF_8.name());

            boolean foundAtLeastOne = false;
            while (true) {
                try {
                    Result result = multiFormatReader.decode(bitmap, hints);
                    res.add(result.getText());
                    foundAtLeastOne = true;

                    // 获取二维码位置信息并将其置白
                    ResultPoint[] points = result.getResultPoints();
                    if (points != null && points.length > 0) {
                        // 计算二维码的大致区域
                        int minX = imageCopy.getWidth();
                        int maxX = 0;
                        int minY = imageCopy.getHeight();
                        int maxY = 0;

                        for (ResultPoint point : points) {
                            int x = (int) point.getX();
                            int y = (int) point.getY();
                            minX = Math.min(minX, x);
                            maxX = Math.max(maxX, x);
                            minY = Math.min(minY, y);
                            maxY = Math.max(maxY, y);
                        }

                        // 扩大清除范围以确保完全覆盖二维码
                        int margin = 5;
                        minX = Math.max(0, minX - margin);
                        maxX = Math.min(imageCopy.getWidth(), maxX + margin);
                        minY = Math.max(0, minY - margin);
                        maxY = Math.min(imageCopy.getHeight(), maxY + margin);

                        // 将二维码区域设置为白色
                        for (int y = minY; y < maxY; y++) {
                            for (int x = minX; x < maxX; x++) {
                                imageCopy.setRGB(x, y, Color.WHITE.getRGB());
                            }
                        }
                    }

                    // 更新光源和二值化图像
                    source = new BufferedImageLuminanceSource(imageCopy);
                    bitmap = new BinaryBitmap(new HybridBinarizer(source));
                } catch (Exception e) {
                    if (!foundAtLeastOne) {
                        // 可以选择是否抛出异常或者记录日志
                        throw new RuntimeException("Failed to decode QR code image", e);
                    }
                    break;
                }
            }

            //画出来看看
//            JFrame frame = new JFrame("Image Viewer");
//            frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
//            BufferedImage newImg = new BufferedImage(imageCopy.getWidth(), imageCopy.getHeight(), BufferedImage.TYPE_INT_RGB);
//            newImg.createGraphics().drawImage(imageCopy, 0, 0, null);
//            JLabel imageLabel = new JLabel(new ImageIcon(imageCopy));
//            frame.add(imageLabel);
//            frame.pack();
//            frame.setVisible(true);
            return res;
        } catch (Exception e) {
            throw new RuntimeException("Failed to decode multiple QR codes from image", e);
        }
    }

    /**
     * 将长字符串分割并生成多个二维码图片
     * 如果字符串超过1000字符，则切割（每个串前添加一个index用作标记），分别生成二维码，最后返回一个image list
     *
     * @param text 要转换的字符串
     * @return 生成的二维码图片文件列表
     */
    public static List<BufferedImage> encodeMultiple(String text) {
        List<BufferedImage> imageFiles = new ArrayList<>();
        int maxLength = MAX_LENGTH_PAGE - 10;

        // 如果字符串不超过1000字符，直接生成一个二维码
        if (text.length() <= maxLength) {
            BufferedImage file = encode(text);
            imageFiles.add(file);
            return imageFiles;
        }

        // 如果字符串超过1000字符，进行分割处理
        int index = 0;
        int start = 0;

        while (start < text.length()) {
            int end = Math.min(start + maxLength, text.length());
            String chunk = text.substring(start, end);

            // 添加索引标记

            String indexedChunk = SPLIT_FLAG + (index + (SPLIT_FLAG + chunk));

            // 生成二维码
            BufferedImage file = encode(indexedChunk);
            imageFiles.add(file);

            start = end;
            index++;
        }

        return imageFiles;
    }

    /**
     * 解析多个二维码图片并将结果按索引顺序重组为原始字符串
     * 注意需要去掉上个方法添加的index标记
     *
     * @param imageFile 二维码图片文件
     * @return 重组后的原始字符串
     */
    public static List<DecodeResult> decodeMultiple(BufferedImage imageFile) {
        return decodeMultipleToList(imageFile)
                .stream()
                .map(content -> {
                    int start = content.indexOf(SPLIT_FLAG);
                    if (start == -1) {
                        return new DecodeResult(content, -1);
                    }
                    int end = content.indexOf(SPLIT_FLAG, start + 1);
                    if (end == -1) {
                        return new DecodeResult(content, -1);
                    }
                    String num = content.substring(start + 1, end);
                    if (StrUtil.isNumeric(num)) {
                        return new DecodeResult(content.substring(end + 1), Integer.parseInt(num));
                    }
                    return new DecodeResult(content, -1);
                })
                .sorted(Comparator.comparingInt(DecodeResult::index)).toList();
    }

    public record DecodeResult(String text, int index) {
    }
}
